package com.unswift.utils;

import java.io.InputStream;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.unswift.annotation.api.Api;
import com.unswift.annotation.api.ApiField;
import com.unswift.annotation.api.ApiMethod;
import com.unswift.cache.MemoryCache;
import com.unswift.core.entity.Message;
import com.unswift.enums.ExceptionEnum;
import com.unswift.enums.LanguageEnum;
import com.unswift.exception.CoreException;

@Api(value="异常消息公共操作类", author="unswift", date="2022-12-16", version="1.0.0")
public final class ExceptionUtils {

	@ApiField("日志对象")
	private static final Logger logger = LoggerFactory.getLogger(ExceptionUtils.class);
	@ApiField("消息缓存名称")
	private static final String MESSAGE_CACHE_NAME="messageMap";
	@ApiField("消息异常缓存名称")
	private static final String MESSAGE_EXCEPTION_CACHE_NAME="messageExceptionMap";
	@ApiField("消息缓存名称")
	private static final Long MESSAGE_CACHE_EXPIRE=-1L;
	@ApiField("本线程消息使用的语言")
	private static ThreadLocal<String> languageLocal = new InheritableThreadLocal<String>();
	@ApiField("内存缓存对象")
	private static MemoryCache memoryCache;
	
	static{
		loadingMessageXml(Thread.currentThread().getContextClassLoader().getResourceAsStream("exception.xml"), "exception.xml");
	}

	@SuppressWarnings("unchecked")
	@ApiMethod(value="加载异常消息xml，放入缓存中", params=@ApiField("异常文件流"))
	public static void loadingMessageXml(InputStream stream, String fileName) {
		try {
			if(ObjectUtils.isEmpty(memoryCache)){
				memoryCache=MemoryCache.getInstance();
			}
			if(memoryCache.exists(fileName)) {
				return ;
			}
			logger.info("加载系统异常消息，文件："+fileName);
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document document = builder.parse(stream);//加载异常XML文件
			NodeList nodeList=document.getElementsByTagName("exception-mapper");//获取到异常映射关系节点
			Node node;
			NamedNodeMap attribute;
			String key, code, exceptionClass, language, cacheKey, exceptionBean, exceptionBeanClass;
			for (int i = 0, length=nodeList.getLength(); i < length; i++) {
				node=nodeList.item(i);
				attribute=node.getAttributes();//获取属性
				if(ObjectUtils.isNotEmpty(attribute)){
					key=attribute.getNamedItem("key").getNodeValue();
					exceptionClass=attribute.getNamedItem("class").getNodeValue();
					memoryCache.setHash(MESSAGE_EXCEPTION_CACHE_NAME, key, exceptionClass, MESSAGE_CACHE_EXPIRE);
				}
			}
			NodeList languageNodeList;
			nodeList=document.getElementsByTagName("message");//获取消息节点
			Node languageNode;
			Message message;
			Class<CoreException> exception;
			for (int i = 0, length=nodeList.getLength(); i < length; i++) {
				node=nodeList.item(i);
				attribute=node.getAttributes();//获取属性
				if(ObjectUtils.isNotEmpty(attribute)){
					key=attribute.getNamedItem("key").getNodeValue();
					code=attribute.getNamedItem("code").getNodeValue();
					exceptionBean = attribute.getNamedItem("exception").getNodeValue();
					if(ObjectUtils.isEmpty(exceptionBean)){
						throw new CoreException(ExceptionEnum.EXCEPTION_NO_CONFIGURED_BEAN.getCode(), String.format(ExceptionEnum.EXCEPTION_NO_CONFIGURED_BEAN.getMessage(), code));
					}
					exceptionBeanClass = memoryCache.getHash(MESSAGE_EXCEPTION_CACHE_NAME, exceptionBean);
					if(ObjectUtils.isEmpty(exceptionBeanClass)){
						throw new CoreException(ExceptionEnum.CANNOT_FIND_EXCEPTION_BEAN.getCode(), String.format(ExceptionEnum.CANNOT_FIND_EXCEPTION_BEAN.getMessage(), exceptionBean));
					}
					exception=ClassUtils.forName(exceptionBeanClass);
					languageNodeList=node.getChildNodes();
					if(ObjectUtils.isEmpty(languageNodeList)){
						throw new CoreException(ExceptionEnum.SET_FIRST_LANGUAGE.getCode(), ExceptionEnum.SET_FIRST_LANGUAGE.getMessage());
					}
					for (int j = 0, length2=languageNodeList.getLength(); j < length2; j++) {
						languageNode=languageNodeList.item(j);
						language=StringUtils.toUpper(languageNode.getNodeName());
						if("#TEXT".equals(language)){
							continue;
						}
						message=new Message();
						message.setKey(key);
						message.setCode(code);
						message.setLanguage(language);
						message.setMessage(languageNode.getTextContent());
						message.setException(exception);
						attribute=languageNode.getAttributes();
						if(ObjectUtils.isEmpty(attribute)){
							node=attribute.getNamedItem("argsOrder");
							if(ObjectUtils.isNotEmpty(node)){
								message.setArgsOrder((List<Integer>)JsonUtils.toJava(node.getNodeValue(), List.class, Integer.class));
							}
						}
						cacheKey=String.format("%s.%s", key, language);
						memoryCache.setHash(MESSAGE_CACHE_NAME, cacheKey, message, MESSAGE_CACHE_EXPIRE);
					}
				}
			}
			memoryCache.set(fileName, true);
		} catch (CoreException e){
			throw e;
		} catch (Exception e) {
			e.printStackTrace();
			throw new CoreException(ExceptionEnum.PARSE_MESSAGE_XML.getCode(), String.format(ExceptionEnum.PARSE_MESSAGE_XML.getMessage(), e.getMessage()), e);
		}
	}
	
	@ApiMethod(value="设置第三方消息列表到缓存中", params=@ApiField("第三方消息列表"))
	public static void loadingMessageList(List<Message> messageList){
		logger.info("开始加载应用消息");
		String cacheKey;
		for (Message message : messageList) {
			cacheKey=String.format("%s.%s", message.getKey(), message.getLanguage());
			memoryCache.setHash(MESSAGE_CACHE_NAME, cacheKey, message, MESSAGE_CACHE_EXPIRE);
		}
		logger.info("加载应用消息完成");
	}
	
	@ApiMethod(value="获取异常消息内容", params=@ApiField("消息key"), returns=@ApiField("消息内容"))
	public static String getMessage(String key){
		Message message=memoryCache.getHash(MESSAGE_CACHE_NAME, String.format("%s.%s", key, getLanguage()));
		if(ObjectUtils.isEmpty(message)){
			throw new CoreException(ExceptionEnum.MESSAGE_NOT_EXIST.getCode(), String.format(ExceptionEnum.MESSAGE_NOT_EXIST.getMessage(), key));
		}
		return message.getMessage();
	}
	
	@ApiMethod(value="根据异常key及参数创建异常", params={@ApiField("异常key"), @ApiField("消息的参数")}, returns=@ApiField("指定的异常，此异常必须继承CoreException类"))
	public static CoreException message(String key, Object...args){
		Message message=memoryCache.getHash(MESSAGE_CACHE_NAME, String.format("%s.%s", key, getLanguage()));
		if(ObjectUtils.isEmpty(message)){
			throw new CoreException(ExceptionEnum.MESSAGE_NOT_EXIST.getCode(), String.format(ExceptionEnum.MESSAGE_NOT_EXIST.getMessage(), key));
		}
		String exceptionMessage=message.getMessage();
		if(ObjectUtils.isNotEmpty(args)){
			if(ObjectUtils.isNotEmpty(message.getArgsOrder())){
				Object[] tempArgs=new Object[args.length];
				for (int i = 0, length=tempArgs.length; i < length; i++) {
					tempArgs[message.getArgsOrder().get(i)]=args[i];
				}
				args=tempArgs;
			}
			exceptionMessage=String.format(exceptionMessage, args);
		}
		return ClassUtils.newInstance(message.getException(), ObjectUtils.toArray(String.class, String.class), message.getCode(), exceptionMessage);
	}
	
	@ApiMethod(value="根据异常key、异常对象及参数创建异常", params={@ApiField("异常key"), @ApiField("异常对象"), @ApiField("异常消息的参数")}, returns=@ApiField("指定的异常，此异常必须继承CoreException类"))
	public static CoreException exception(String key, Throwable e, Object...args){
		Message message=memoryCache.getHash(MESSAGE_CACHE_NAME, String.format("%s.%s", key, getLanguage()));
		if(ObjectUtils.isEmpty(message)){
			throw new CoreException(ExceptionEnum.MESSAGE_NOT_EXIST.getCode(), String.format(ExceptionEnum.MESSAGE_NOT_EXIST.getMessage(), key));
		}
		String exceptionMessage=message.getMessage();
		if(ObjectUtils.isNotEmpty(args)){
			if(ObjectUtils.isNotEmpty(message.getArgsOrder())){
				Object[] tempArgs=new Object[args.length];
				for (int i = 0, length=tempArgs.length; i < length; i++) {
					tempArgs[message.getArgsOrder().get(i)]=args[i];
				}
				args=tempArgs;
			}
			exceptionMessage=String.format(exceptionMessage, args);
		}
		return ClassUtils.newInstance(message.getException(), ClassUtils.toArray(String.class, String.class, Throwable.class), message.getCode(), exceptionMessage, e);
	}
	
	@ApiMethod(value="布尔值为true时异常", params={@ApiField("布尔值"), @ApiField("异常key"), @ApiField("异常消息的参数")})
	public static void trueException(boolean source, String key, Object...args){
		if(source){
			throw message(key, args);
		}
	}
	
	@ApiMethod(value="布尔值为false时异常", params={@ApiField("布尔值"), @ApiField("异常key"), @ApiField("异常消息的参数")})
	public static void falseException(boolean source, String key, Object...args){
		if(!source){
			throw message(key, args);
		}
	}
	
	@ApiMethod(value="对象为空时抛出异常", params={@ApiField("对象"), @ApiField("异常key"), @ApiField("异常消息的参数")})
	public static void empty(Object source, String key, Object...args){
		if(ObjectUtils.isEmpty(source)){
			throw message(key, args);
		}
	}
	
	@ApiMethod(value="对象不为空时抛出异常", params={@ApiField("对象"), @ApiField("异常key"), @ApiField("异常消息的参数")})
	public static void notEmpty(Object source, String key, Object...args){
		if(ObjectUtils.isNotEmpty(source)){
			throw message(key, args);
		}
	}
	
	@ApiMethod(value="两个对象相等时抛出异常", params={@ApiField("对象1"), @ApiField("对象2"), @ApiField("异常key"), @ApiField("异常消息的参数")})
	public static void equals(Object source, Object target, String key, Object...args){
		if(ObjectUtils.equals(source, target, true)){
			throw message(key, args);
		}
	}
	
	@ApiMethod(value="两个对象不相等时抛出异常", params={@ApiField("对象1"), @ApiField("对象2"), @ApiField("异常key"), @ApiField("异常消息的参数")})
	public static void notEquals(Object source, Object target, String key, Object...args){
		if(!ObjectUtils.equals(source, target, true)){
			throw message(key, args);
		}
	}
	
	@ApiMethod(value="获取异常使用的语言，如果未设置，则使用中文", returns=@ApiField("当前线程的语言"))
	public static String getLanguage() {
		String language=languageLocal.get();
		return ObjectUtils.init(language, LanguageEnum.ZH_CN.getLanguage());
	}
	
	@ApiMethod(value="设置异常使用的语言", params=@ApiField("语言"))
	public static void setLanguage(String language) {
		languageLocal.set(language);
	}
	
	@ApiMethod(value="获取异常得堆栈信息", params=@ApiField("异常"))
	public static String getStackTrace(Exception e) {
		return null;
	}
}
